﻿namespace System.ServiceModel.DomainServices
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.ServiceModel.DomainServices.Client;

    internal static class TypeUtility
    {
        private static HashSet<Type> predefinedTypes = new HashSet<Type> { typeof(string), typeof(decimal), typeof(DateTime), typeof(DateTimeOffset), typeof(TimeSpan), typeof(Guid), typeof(Uri) };
        private static string[] systemAssemblyPublicKeyTokens = new string[] { "b77a5c561934e089", "31bf3856ad364e35", "b03f5f7f11d50a3a", "7cec85d7bea7798e" };

        internal static bool DefinitionIsAssignableFrom(this Type genericTypeDefinition, Type derivedType)
        {
            Type genericType = null;
            return genericTypeDefinition.DefinitionIsAssignableFrom(derivedType, out genericType);
        }

        internal static bool DefinitionIsAssignableFrom(this Type genericTypeDefinition, Type derivedType, out Type genericType)
        {
            genericType = derivedType;
            while (genericType != null)
            {
                if (genericTypeDefinition.IsInterface)
                {
                    bool flag = false;
                    foreach (Type type in genericType.GetInterfaces().Concat<Type>(new Type[] { derivedType }))
                    {
                        if (type.IsGenericType && (genericTypeDefinition == type.GetGenericTypeDefinition()))
                        {
                            flag = true;
                            genericType = type;
                            break;
                        }
                    }
                    if (flag)
                    {
                        break;
                    }
                }
                else if (genericType.IsGenericType && (genericTypeDefinition == genericType.GetGenericTypeDefinition()))
                {
                    break;
                }
                genericType = genericType.BaseType;
            }
            return (genericType != null);
        }

        internal static Type FindIEnumerable(Type seqType)
        {
            if ((seqType != null) && (seqType != typeof(string)))
            {
                if (seqType.IsArray)
                {
                    return typeof(IEnumerable<>).MakeGenericType(new Type[] { seqType.GetElementType() });
                }
                if (seqType.IsGenericType)
                {
                    foreach (Type type in seqType.GetGenericArguments())
                    {
                        Type type2 = typeof(IEnumerable<>).MakeGenericType(new Type[] { type });
                        if (type2.IsAssignableFrom(seqType))
                        {
                            return type2;
                        }
                    }
                }
                Type[] interfaces = seqType.GetInterfaces();
                if ((interfaces != null) && (interfaces.Length > 0))
                {
                    foreach (Type type3 in interfaces)
                    {
                        Type type4 = FindIEnumerable(type3);
                        if (type4 != null)
                        {
                            return type4;
                        }
                    }
                }
                if ((seqType.BaseType != null) && (seqType.BaseType != typeof(object)))
                {
                    return FindIEnumerable(seqType.BaseType);
                }
            }
            return null;
        }

        public static Type GetElementType(Type type)
        {
            if (!IsPredefinedSimpleType(type))
            {
                if (type.HasElementType)
                {
                    return type.GetElementType();
                }
                Type type2 = FindIEnumerable(type);
                if (type2 != null)
                {
                    return type2.GetGenericArguments()[0];
                }
            }
            return type;
        }

        public static Type GetNonNullableType(Type type)
        {
            if (!IsNullableType(type))
            {
                return type;
            }
            return type.GetGenericArguments()[0];
        }

        public static bool IsComplexType(Type type)
        {
            if (!typeof(ComplexObject).IsAssignableFrom(type))
            {
                return false;
            }
            return true;
        }

        public static bool IsComplexTypeCollection(Type type)
        {
            return (IsSupportedCollectionType(type) && IsComplexType(GetElementType(type)));
        }

        public static bool IsNullableType(Type type)
        {
            return (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>)));
        }

        public static bool IsPredefinedDictionaryType(Type type)
        {
            Type type2;
            if (!typeof(IDictionary<,>).DefinitionIsAssignableFrom(type, out type2))
            {
                return false;
            }
            return Enumerable.All<Type>(type2.GetGenericArguments(), (Func<Type, bool>) (t => IsPredefinedSimpleType(t)));
        }

        public static bool IsPredefinedListType(Type type)
        {
            return (IsSupportedCollectionType(type) && IsPredefinedSimpleType(GetElementType(type)));
        }

        public static bool IsPredefinedSimpleType(Type type)
        {
            type = GetNonNullableType(type);
            return (((type.IsPrimitive && (type != typeof(IntPtr))) && (type != typeof(UIntPtr))) || (type.IsEnum || (predefinedTypes.Contains(type) || (BinaryTypeUtility.IsTypeBinary(type) || (string.Compare(type.FullName, "System.Xml.Linq.XElement", StringComparison.Ordinal) == 0)))));
        }

        public static bool IsPredefinedType(Type type)
        {
            if (!IsPredefinedSimpleType(type) && !IsPredefinedListType(type))
            {
                return IsPredefinedDictionaryType(type);
            }
            return true;
        }

        public static bool IsSupportedCollectionType(Type type)
        {
            if ((!type.IsArray && (!type.IsGenericType || (type.GetGenericTypeDefinition() != typeof(IEnumerable<>)))) && (!typeof(IList).IsAssignableFrom(type) || (type.GetConstructor(Type.EmptyTypes) == null)))
            {
                return false;
            }
            return true;
        }

        public static bool IsSupportedComplexType(Type type)
        {
            if (!IsComplexType(type))
            {
                return IsComplexTypeCollection(type);
            }
            return true;
        }

        internal static bool IsSystemAssembly(this Assembly assembly)
        {
            return IsSystemAssembly(assembly.FullName);
        }

        internal static bool IsSystemAssembly(this AssemblyName assemblyName)
        {
            return IsSystemAssembly(assemblyName.FullName);
        }

        internal static bool IsSystemAssembly(string assemblyFullName)
        {
            int index = assemblyFullName.IndexOf("PublicKeyToken=", StringComparison.OrdinalIgnoreCase);
            if (index == 0)
            {
                return false;
            }
            string publicKeyToken = assemblyFullName.Substring(index + 15);
            return Enumerable.Any<string>(systemAssemblyPublicKeyTokens, (Func<string, bool>) (p => p.Equals(publicKeyToken, StringComparison.OrdinalIgnoreCase)));
        }
    }
}

